package br.com.rafaelSys.importacao;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import br.com.rafaelSys.entidades.Ativo;
import br.com.rafaelSys.entidades.AtivoSerie;

public class Importador {

	private Ativo ativo;
	private EntityManager entityManager;

	private int criacoes;
	private int atualizacoes;

	public Importador(Ativo ativo) {
		this.ativo = ativo;
	}

	public Importador(Ativo instance, EntityManager entityManager) {
		this.ativo = instance;
		this.entityManager = entityManager;
	}

	public URL montaUrl(String simbolo, Calendar dataInicial, Calendar dataFinal) throws MalformedURLException {
		StringBuilder sb = new StringBuilder(200);
		sb.append("http://ichart.yahoo.com/table.csv?s=");
		sb.append(simbolo);
		sb.append("&d=");
		sb.append(dataFinal.get(Calendar.MONTH));
		sb.append("&e=");
		sb.append(dataFinal.get(Calendar.DATE));
		sb.append("&f=");
		sb.append(dataFinal.get(Calendar.YEAR));
		sb.append("&g=d&a=");
		sb.append(dataInicial.get(Calendar.MONTH));
		sb.append("&b=");
		sb.append(dataInicial.get(Calendar.DATE));
		sb.append("&c=");
		sb.append(dataInicial.get(Calendar.YEAR));
		sb.append("&ignore=.csv");
		System.out.println("URL gerada: " + sb.toString());
		return new URL(sb.toString());
	}

	public File baixaArquivo(String simbolo, Calendar dataInicial, Calendar dataFinal) throws FileNotFoundException {

		InputStream in = null;
		OutputStream out = null;
		String destino = null;
		String time = null;

		try {
			time = dataFinal.get(Calendar.YEAR) + "-" + (dataFinal.get(Calendar.MONTH) + 1) + "-" + dataFinal.get(Calendar.DATE);
			time += "." + dataInicial.get(Calendar.YEAR) + "-" + (dataInicial.get(Calendar.MONTH) + 1) + "-" + dataInicial.get(Calendar.DATE);
			destino = simbolo + "." + time + ".csv";

			System.out.println(destino);
			SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
			URL url = montaUrl(simbolo, dataInicial, dataFinal);
			System.out.println("Baixando arquivo... per�odo, de: " + sdf.format(dataInicial.getTime()) + " at�: " + sdf.format(dataFinal.getTime()));

			in = url.openStream();

			System.out.println("Arquivo baixado! " + in.available());
			out = new FileOutputStream(destino);

			// Copia bytes a partir da URL para fluxo de sa�da
			byte[] buffer = new byte[4096];
			int bytes_read;
			System.out.println("Copiando: " + simbolo);
			System.out.println("\t" + url);
			while ((bytes_read = in.read(buffer)) != -1)
				out.write(buffer, 0, bytes_read);
			System.out.println("Terminado: " + simbolo + "\n");
		}

		// Houve exce��o? Vamos exibir o erro
		catch (FileNotFoundException e) {
			throw e;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally { // Temos sempre que fechar os stream.
			try {
				in.close();
				out.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		File file = new File(destino);

		System.out.println(file.getAbsolutePath());
		return file;
	}

	private Query query;

	private void processaArquivo(File arquivo) throws FileNotFoundException {

		query = entityManager.createNamedQuery("AtivoSerie.findUnique");

		System.out.println("Processando arquivo... " + arquivo.length());

		if (arquivo.length() == 0) {
			System.out.println("Arquivo vazio! ");
			return;
		}

		try {
			BufferedReader buff = new BufferedReader(new FileReader(arquivo));

			String linha = buff.readLine();
			linha = buff.readLine();
			while (linha != null) {
				processaLinha(linha);
				linha = buff.readLine();
			}
		} catch (FileNotFoundException e) {
			throw e;
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void processaLinha(String linha) {

		String[] vars = linha.split(",");

		if (vars.length == 7) {
			Date data = null;
			Double open = null;
			Double high = null;
			Double low = null;
			Double close = null;
			Long volume = null;
			Double adj = null;

			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
			try {
				data = df.parse(vars[0]);
			} catch (ParseException e) {
				e.printStackTrace();
			}

			open = Double.parseDouble(vars[1]);
			high = Double.parseDouble(vars[2]);
			low = Double.parseDouble(vars[3]);
			close = Double.parseDouble(vars[4]);
			volume = Long.parseLong(vars[5]);
			adj = Double.parseDouble(vars[6]);

			query.setParameter("ativo", ativo);
			query.setParameter("data", data);
			AtivoSerie serie;

			try {
				serie = (AtivoSerie) query.getSingleResult();

				if (serie != null) {
					serie.atualizaValores(open, high, low, close, volume, adj);
					entityManager.merge(serie);
					atualizacoes++;
				}

			} catch (javax.persistence.NoResultException nre) {
				serie = new AtivoSerie(ativo, data, open, high, low, close, volume, adj);
				entityManager.persist(serie);
				criacoes++;
			}

		} else
			System.err.println("vars.length != 8");
	}

	public void atualizarAtivo() throws FileNotFoundException {
		// TODO Auto-generated method stub

		Calendar atualizacao = Calendar.getInstance();
		atualizacao.setTime(ativo.getUltimaAtualizacao());

		File arquivo = baixaArquivo(ativo.getSimbolo(), atualizacao, Calendar.getInstance());
		processaArquivo(arquivo);

		entityManager.flush();
		System.out.println("Criacoes" + criacoes);
		System.out.println("Atualizacoes" + atualizacoes);
		arquivo.delete();
	}

	public void cargaInicial() throws FileNotFoundException {
		// TODO Auto-generated method stub
		Calendar dataInicial = Calendar.getInstance();
		dataInicial.setTime(ativo.getDataCargaInicial());

		File arquivo = baixaArquivo(ativo.getSimbolo(), dataInicial, Calendar.getInstance());
		processaArquivo(arquivo);

		entityManager.flush();
		System.out.println("Criacoes" + criacoes);
		System.out.println("Atualizacoes" + atualizacoes);
		arquivo.delete();
	}

	public int getCriacoes() {
		return criacoes;
	}

	public void setCriacoes(int criacoes) {
		this.criacoes = criacoes;
	}

	public int getAtualizacoes() {
		return atualizacoes;
	}

	public void setAtualizacoes(int atualizacoes) {
		this.atualizacoes = atualizacoes;
	}

	public int getSoma() {
		return criacoes + atualizacoes;
	}

}
